package com.zoweunion.mechanic.util.common;

import com.alibaba.fastjson.JSON;
import com.zoweunion.mechanic.util.DateUtil;
import com.zoweunion.mechanic.util.calculate.CalculateVarianceUtil;
import com.zoweunion.mechanic.util.constants.Constants;
import org.apache.commons.lang.StringUtils;

import java.math.BigDecimal;
import java.time.LocalDate;
import java.time.LocalDateTime;
import java.util.*;

/**
 * 车辆设备数据处理统计工具类
 */
public class CarDataStatisticsUtil {


    /**
     * 获取每日数据差
     *
     * @param peakDataList 每日峰值数据
     * @return
     */
    public static List<Map<String, Object>> getConsumption(List<Map<String, Object>> peakDataList, String tag) {
        int dataSize = peakDataList.size();
        if (dataSize == 0) {
            return Collections.emptyList();
        }
        List<Map<String, Object>> dataList = new ArrayList<>((int) (peakDataList.size() / 0.75));
        for (int i = 0; i < dataSize; i++) {
            String date = peakDataList.get(i).get("sample_time").toString().substring(0, 10);
            Map<String, Object> fuelConsumptionMap = new HashMap<>(5);
            fuelConsumptionMap.put("date", date);
            fuelConsumptionMap.put("value", operatingHours(peakDataList.get(i), tag));
            dataList.add(fuelConsumptionMap);
        }
        return dataList;
    }

    /**
     * 获取每日数据差
     *
     * @param workHoursList 工作数据列表
     * @return
     */
    public static List<Map<String, Object>> getConsumption(List<Map<String, Object>> workHoursList) {
        int dataSize = workHoursList.size();
        if (dataSize == 0) {
            return Collections.emptyList();
        }
        List<Map<String, Object>> dataList = new ArrayList<>((int) (workHoursList.size() / 0.70));
        for (Map<String, Object> data : workHoursList) {
            dataList.add(workHours(data));
        }
        return dataList;
    }

    public static Map<String, Object> workHours(Map<String, Object> data){
        Map<String, Object> dataMap = new HashMap<>(5);
        String date = data.get("sample_date").toString().substring(0, 10);
        dataMap.put("date", date);
        if (data.get("work_hours_json") != null && !"{}".equals(data.get("work_hours_json").toString())) {
            dataMap.put("value", JSON.parseObject(data.get("work_hours_json").toString()).get("workHours"));
        } else {
            dataMap.put("value", "0.00");
        }
        return dataMap;
    }

    public static String distanceMinuteFromDay(String btime) {
        if ("2000-00-00 00:00:00".equals(btime)) {
            return "0.00";
        }
        return distanceMinute(DateUtil.parseTime(btime.substring(0, 10) + " 00:00:00"), DateUtil.parseTime(btime.substring(0, 17) + "00"));
    }

    public static String distanceMinute(String atime, String btime) {
        if ("2000-00-00 00:00:00".equals(atime) || "2000-00-00 00:00:00".equals(btime)) {
            return "0";
        }
        return distanceMinute(DateUtil.parseTime(atime.substring(0, 17) + "00"), DateUtil.parseTime(btime.substring(0, 17) + "00"));
    }

    private static String distanceMinute(LocalDateTime atime, LocalDateTime btime){
        long minute = DateUtil.getDistanceMinute(atime, btime);
        return Math.abs(minute) / 60D + "";
    }

    public static double correctFuelGauge(String fuelGaugeValue) {
        return correctFuelGauge(Double.valueOf(fuelGaugeValue));
    }
    public static double correctFuelGauge(double fuelGaugeValue){
        if (fuelGaugeValue < 0) {
            fuelGaugeValue = 0;
        } else if (fuelGaugeValue > 100) {
            fuelGaugeValue = 100;
        }
        return fuelGaugeValue;
    }

    public static double operatingHours(Map<String, Object> peakData, String tag){
        String minFuelConsumption = peakData.get("min_" + tag).toString();
        String maxFuelConsumption = peakData.get("max_" + tag).toString();
        double fuelConsumption = Double.valueOf(maxFuelConsumption) - Double.valueOf(minFuelConsumption);
        double value = CarDataStatisticsUtil.round(fuelConsumption, 1);
        if (value < 0) {
            value = 0;
        } else if (value > 24) {
            value = 24;
        }
        return value;
    }


    /**
     * 提供精确的小数位四舍五入处理。
     *
     * @param v     需要四舍五入的数字
     * @param scale 小数点后保留几位
     * @return 四舍五入后的结果
     */
    public static double round(double v, int scale) {
        return roundBigDecimal(v, scale).doubleValue();
    }
    /**
     * 提供精确的小数位四舍五入处理。
     *
     * @param v     需要四舍五入的数字
     * @param scale 小数点后保留几位
     * @return 四舍五入后的结果
     */
    public static String roundStr(double v, int scale) {
        return roundBigDecimal(v, scale).toString();
    }
    /**
     * 提供精确的小数位四舍五入处理。
     *
     * @param v     需要四舍五入的数字
     * @param scale 小数点后保留几位
     * @return 四舍五入后的结果
     */
    public static BigDecimal roundBigDecimal(double v, int scale) {
        if (scale < 0) {
            throw new IllegalArgumentException("The scale must be a positive integer or zero");
        }
        BigDecimal b = BigDecimal.valueOf(v);
        BigDecimal one = new BigDecimal("1");
        return b.divide(one, scale, BigDecimal.ROUND_HALF_UP);
    }

    public static boolean equalsZero(Object obj) {
        return !isBlank(obj) && "0".equals(obj.toString());
    }

    public static boolean isBlank(Object obj) {
        return obj == null || StringUtils.isBlank(obj.toString());
    }

    public static void sortASC(List<Map<String, Object>> runMapList) {
        // 排序 升序
        runMapList.sort((o1, o2) -> {
            LocalDate date1 = DateUtil.parseDate(o1.get("date").toString());
            LocalDate date2 = DateUtil.parseDate(o2.get("date").toString());
            if (date1.isBefore(date2)) {
                return -1;
            } else if (date1.equals(date2)) {
                return 0;
            } else {
                return 1;
            }
        });
    }

    /**
     * 车数据设置单位
     * @param carDataMap
     * @param intelligentTemplateDetails
     * @return
     */
    public static Map<String, Object> getCarDatasetUnit(Map<String, Object> carDataMap, List<Map<String, Object>> intelligentTemplateDetails) {
        int size = (int) (intelligentTemplateDetails.size() / 0.7);
        // 定义存放变量的map
        Map<String, Object> dataMap = new LinkedHashMap<>(size);

        for (Map<String, Object> details : intelligentTemplateDetails) {
            if (details.get("display") != null && "1".equals(details.get("display").toString())) {
                continue;
            }
            String tag = CarDataStatisticsUtil.formatTag(details.get("tag").toString());
            String tagValue = "";
            String unit = details.get("company").toString();
            if (carDataMap != null) {
                if (carDataMap.get(tag) == null) {
                    tagValue = "0";
                } else {
                    tagValue = carDataMap.get(tag).toString();
                }
            }
            tag = CarDataStatisticsUtil.formatTag(tag);
            dataMap.put(tag, tagValue + unit);
        }
        return dataMap;
    }

    public static Map<String, Object> getDataName(List<Map<String, Object>> intelligentTemplateDetails) {
        int size = (int) (intelligentTemplateDetails.size() / 0.7);
        // 定义存放变量的map
        Map<String, Object> variableMap = new LinkedHashMap<>();

        for (Map<String, Object> details : intelligentTemplateDetails) {
            if (details.get("display") != null && "1".equals(details.get("display").toString())) {
                continue;
            }
            String tag = details.get("tag").toString();

            tag = CarDataStatisticsUtil.formatTag(tag);
            variableMap.put(tag, details.get("name").toString());
        }
        return variableMap;
    }

    public static void setHourData(List<Map<String, Object>> dataMapList, LocalDate endTime, Map<String, Object> resultMap) {
        // 今日工时
        if (LocalDate.now().equals(endTime)) {
            resultMap.put("todayHour", dataMapList.get(dataMapList.size() - 1).get("value"));
        }
        // 总工时
        resultMap.put("totalHour", CarDataStatisticsUtil.round(dataMapList.stream().mapToDouble(m1 -> Double.valueOf(m1.get("value").toString())).sum(), 1));
        // 平均工时
        double avgHour = 0.0D;
        OptionalDouble avgHourOpt = dataMapList.stream()
                .filter(runMap -> !"0.0".equals(runMap.get("value").toString()))
                .mapToDouble(m1 -> Double.valueOf(m1.get("value").toString())).average();
        if (avgHourOpt.isPresent()) {
            avgHour = avgHourOpt.getAsDouble();
        }
        resultMap.put("avgHour", CarDataStatisticsUtil.round(avgHour, 1));
        // 工作天数
        resultMap.put("workDays", dataMapList.stream().filter(runMap -> !"0.0".equals(runMap.get("value").toString())).count());

    }



    public static void setSampleTimeTag(LinkedList<Map<String, Object>> intelligentTemplateDetails) {
        Map<String, Object> sampleTimeMap = new HashMap<>(3);
        sampleTimeMap.put("name", "采样时间");
        sampleTimeMap.put("tag", "sample_time");
        sampleTimeMap.put("company", "");
        sampleTimeMap.put("sort_number", "0");
        sampleTimeMap.put("display", "0");
        intelligentTemplateDetails.addFirst(sampleTimeMap);
    }


    /**
     * 对数据进行标准值比较过滤
     *
     * @return
     */
    public static ArrayList<Map<String, Object>> locationStandardDeviationFilter(ArrayList<Map<String, Object>> locationHistoryList) {
        double[] longitudes = locationHistoryList.stream().mapToDouble(map -> Double.parseDouble(map.get(Constants.THINGS_GPSlongitude).toString())).toArray();
        double[] latitudes = locationHistoryList.stream().mapToDouble(map -> Double.parseDouble(map.get(Constants.THINGS_GPSlatitude).toString())).toArray();

        // 经纬度的平均值
        double longitudeAverage = CalculateVarianceUtil.average(longitudes);
        double latitudeAverage = CalculateVarianceUtil.average(latitudes);

        // 经纬度的标准方差/标准误差
        double longitudeSD = CalculateVarianceUtil.standardDeviation(longitudes);
        double latitudeSD = CalculateVarianceUtil.standardDeviation(latitudes);

        System.out.println("longitudeSD: " + longitudeSD + ", latitudeSD: " + latitudeSD);

        ArrayList<Map<String, Object>> locationList = new ArrayList<>();
        HashMap<String, Object> locationObj;

        for (Map<String, Object> location : locationHistoryList) {

            double gpslongitude = Double.parseDouble(location.get(Constants.THINGS_GPSlongitude).toString());
            if (gpslongitude < (longitudeAverage - longitudeSD) || gpslongitude > (longitudeAverage + longitudeSD)) {
                continue;
            }
            double gpslatitude = Double.parseDouble(location.get(Constants.THINGS_GPSlatitude).toString());
            if (gpslatitude < (latitudeAverage - latitudeSD) || gpslatitude > (latitudeAverage + latitudeSD)) {
                continue;
            }
            locationObj = new HashMap<>(4);
            locationObj.put(Constants.THINGS_GPSlatitude, gpslatitude);
            locationObj.put(Constants.THINGS_GPSlongitude, gpslongitude);

            locationList.add(locationObj);
        }
        return locationList;
    }

    /**
     * 根据约定过滤错误数据,相邻数据相等的都不要
     *
     * @param locationHistoryList
     * @return
     */
    public static ArrayList<Map<String, Object>> locationFilter(ArrayList<Map<String, Object>> locationHistoryList) {
        ArrayList<Map<String, Object>> locationList = new ArrayList<>();
        int size = locationHistoryList.size();
        Double gpslongitudePre = null,
                gpslatitudePre = null,
                gpslongitudeRepeat = null,
                gpslatitudeRepeat = null,
                gpslongitude,
                gpslatitude;
        for (int i = 1; i < size; i++) {
            if (i == 1) {

                gpslongitudePre = Double.parseDouble(locationHistoryList.get(0).get(Constants.THINGS_GPSlongitude).toString());
                gpslatitudePre = Double.parseDouble(locationHistoryList.get(0).get(Constants.THINGS_GPSlatitude).toString());
            }
            gpslongitude = Double.parseDouble(locationHistoryList.get(i).get(Constants.THINGS_GPSlongitude).toString());
            gpslatitude = Double.parseDouble(locationHistoryList.get(i).get(Constants.THINGS_GPSlatitude).toString());

            Map<String, Object> locationObj;

            // 判断上下连个是否重复
            if (!(gpslatitude.equals(gpslatitudePre) && gpslongitude.equals(gpslongitudePre))) {
                // 当上下两个不重复时，判断当前前数据是否与上次的重复数据相等，相等则不处理
                if (!(gpslatitude.equals(gpslatitudeRepeat) && gpslongitude.equals(gpslongitudeRepeat))) {

                    // 判断上下两个精度番位在0.001范围内
                    if (Math.abs(gpslatitude - gpslatitudePre) < 0.0008
                            && Math.abs(gpslongitude - gpslongitudePre) < 0.0008) {
                        locationObj = new HashMap<>(4);
                        locationObj.put(Constants.THINGS_GPSlongitude, gpslongitudePre);
                        locationObj.put(Constants.THINGS_GPSlatitude, gpslatitudePre);
                        locationList.add(locationObj);
                        gpslongitudeRepeat = null;
                        gpslatitudeRepeat = null;
                    }
                }
            } else {
                gpslongitudeRepeat = gpslongitude;
                gpslatitudeRepeat = gpslatitude;
            }
            gpslongitudePre = Double.parseDouble(locationHistoryList.get(i).get(Constants.THINGS_GPSlongitude).toString());
            gpslatitudePre = Double.parseDouble(locationHistoryList.get(i).get(Constants.THINGS_GPSlatitude).toString());
        }
        return locationList;
    }


    /**
     * 格式化智能模板标签
     *
     * @param tag
     * @return
     */
    public static String formatTag(String tag) {
        return tag.trim().replaceAll("\\.", "_").replaceAll(" ", "_").replaceAll("-", "_");
    }
}
